package com.bst.bsj.portal.yun.service.impl;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.util.ByteArrayBuffer;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.utils.IOUtils;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.OSSObjectSummary;
import com.aliyun.oss.model.ObjectListing;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;
import com.bst.bsj.portal.yun.service.FolderItem;
import com.bst.bsj.portal.yun.service.ImageYunService;
import com.bst.bsj.spring.util.ConfigUtil;
import com.homewaimai.common.lang.StringUtil;

@Service("imageYunService")
public class AliYunServiceImpl implements ImageYunService, InitializingBean {

    public static final Log logger            = LogFactory.getLog(AliYunServiceImpl.class);

    private String          IMAGE_SIZE        = "1e_%width%w_%height%h_1c_0i_1o_90Q_1x.";

    private String          outputDir;

    private OSSClient       ossClient;

    // 批量上传最大上传线程数
    private int             MAX_UPLOAD_THREAD = 8;

    private String          accesskeyId;

    private String          accesskeySecret;

    private String          imgBucket;

    private String          imgDomain;

    public AliYunServiceImpl(){
        accesskeyId = ConfigUtil.getProperties().getProperty("aliyun.accesskeyid");
        accesskeySecret = ConfigUtil.getProperties().getProperty("aliyun.accesskeysecret");
        imgBucket = ConfigUtil.getProperties().getProperty("aliyun.imgbucket");
        imgDomain = ConfigUtil.getProperties().getProperty("image.domain");
        outputDir = ConfigUtil.getProperties().getProperty("upload.path");
    }

    public String getImageYunProvider() {
        return ALIYUN_PROVIDER;
    }

    public String getImageYunDomain() {
        return imgDomain;
    }

    public String getAccesskeyId() {
        return accesskeyId;
    }

    public void setAccesskeyId(String accesskeyId) {
        this.accesskeyId = accesskeyId;
    }

    public String getAccesskeySecret() {
        return accesskeySecret;
    }

    public void setAccesskeySecret(String accesskeySecret) {
        this.accesskeySecret = accesskeySecret;
    }

    public String getImgBucket() {
        return imgBucket;
    }

    public void setImgBucket(String imgBucket) {
        this.imgBucket = imgBucket;
    }

    public String getImgDomain() {
        return imgDomain;
    }

    public void setImgDomain(String imgDomain) {
        this.imgDomain = imgDomain;
    }

    public String getThumbImg(String sourceImg, int width, int height) {
        String targetImg = sourceImg;
        if (null != sourceImg) {
            String postImage = IMAGE_SIZE.replace("%width%", String.valueOf(width)).replace("%height%",
                                                                                            String.valueOf(height));
            String formater = "jpg";
            if (sourceImg.endsWith("png")) {
                formater = "png";
            } else if (sourceImg.endsWith("gif")) {
                formater = "gif";
            }
            postImage = postImage + formater;

            int pos = sourceImg.indexOf("@");
            if (pos != -1) {
                targetImg = sourceImg.substring(0, pos) + "@" + postImage;
            } else {
                targetImg = sourceImg + "@" + postImage;
            }
        }
        return targetImg;
    }

    // 上传文件
    private static PutObjectResult uploadFile(OSSClient client, String bucketName, String key, File _file)
                                                                                                          throws OSSException,
                                                                                                          ClientException,
                                                                                                          IOException {
        String filename = _file.getName();
        ObjectMetadata objectMeta = new ObjectMetadata();
        objectMeta.setContentLength(_file.length());
        if (filename.endsWith("png")) {
            objectMeta.setContentType("image/png");
        } else if (filename.endsWith("gif")) {
            objectMeta.setContentType("image/gif");
        } else if (filename.endsWith("jpg") || filename.endsWith("jpeg")) {
            objectMeta.setContentType("image/jpg");
        }
        if (key.startsWith("/")) {
            key = key.substring(1);
        }
        InputStream input = new FileInputStream(_file);
        try {
            return client.putObject(bucketName, key, input, objectMeta);
        } catch (Exception e) {
            logger.error("uploadFile", e);
            return null;
        } finally {
            input.close();
        }
    }

    // 下载文件
    private byte[] downloadFile(OSSClient client, String bucketName, String key) throws OSSException, ClientException {
        try {
            GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);
            OSSObject ossObject = client.getObject(getObjectRequest);

            ByteArrayBuffer output = new ByteArrayBuffer((int) ossObject.getObjectMetadata().getContentLength());
            int bufSize = 1024;
            try {
                byte[] buffer = new byte[bufSize];
                int bytesRead;
                while ((bytesRead = ossObject.getObjectContent().read(buffer)) > -1) {
                    output.append(buffer, 0, bytesRead);
                }
            } catch (IOException e) {
                logger.error("downloadFile error", e);
            } finally {
                IOUtils.safeClose(ossObject.getObjectContent());
            }
            return output.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public boolean writeFile(String fileKey, byte[] datas, Boolean auto) throws Exception {
        try {
            String filePathKey = fileKey;
            if (filePathKey.startsWith("/")) {
                filePathKey = filePathKey.substring(1);
            }
            ObjectMetadata objectMeta = new ObjectMetadata();
            if (fileKey.endsWith("png")) {
                objectMeta.setContentType("image/png");
            } else if (fileKey.endsWith("gif")) {
                objectMeta.setContentType("image/gif");
            } else if (fileKey.endsWith("jpg") || fileKey.endsWith("jpeg")) {
                objectMeta.setContentType("image/jpg");
            }
            objectMeta.setContentLength(datas.length);
            ossClient.putObject(imgBucket, filePathKey, new ByteArrayInputStream(datas), objectMeta);
            return true;
        } catch (Exception e) {
            logger.error("uploadFile", e);
        }
        return false;
    }

    public boolean writeFile(String fileKey, String datas) throws Exception {
        return writeFile(fileKey, datas.getBytes(), true);
    }

    public boolean writeFile(String fileKey, File _file, Boolean auto) throws Exception {
        PutObjectResult putObjectResult = uploadFile(ossClient, imgBucket, fileKey, _file);
        if (null != putObjectResult) {
            return true;
        }
        return false;
    }

    public String readFile(String fileKey) throws Exception {
        byte[] bytes = readBytes(fileKey);
        if (null != bytes) {
            return new String(bytes, "UTF-8");
        }
        return null;
    }

    public boolean deleteFile(String file) throws Exception {
        ossClient.deleteObject(imgBucket, file);
        return true;
    }

    public byte[] readBytes(String fileKey) throws Exception {
        return downloadFile(ossClient, imgBucket, fileKey);
    }

    public List<FolderItem> readDir(String path) throws Exception {
        List<FolderItem> folderList = new ArrayList<FolderItem>();
        ObjectListing objects = ossClient.listObjects(imgBucket, path);
        List<OSSObjectSummary> list = objects.getObjectSummaries();
        List<String> filesList = new ArrayList<String>();
        for (OSSObjectSummary ossObjectSummary : list) {
            if (!ossObjectSummary.getKey().endsWith("/")) {
                filesList.add(ossObjectSummary.getKey());
                FolderItem folderItem = new FolderItem();
                folderItem.setDate(ossObjectSummary.getLastModified());
                folderItem.setName(ossObjectSummary.getKey());
                folderItem.setSize(ossObjectSummary.getSize());
                folderItem.setType("File");
                folderList.add(folderItem);
            }
        }
        return folderList;
    }

    public String getOutputDir() {
        return outputDir;
    }

    public void setOutputDir(String outputDir) {
        this.outputDir = outputDir;
    }

    public String getUploadToken() throws Exception {
        return null;
    }

    @Override
    public boolean writeFiles(List<String> fileKeys, List<File> _files) throws Exception {
        // 批量上传逻辑
        ExecutorService executorService = Executors.newFixedThreadPool(MAX_UPLOAD_THREAD);
        List<String> eTags = Collections.synchronizedList(new ArrayList<String>());

        int fileSize = fileKeys.size();
        int everyThreadTaskSize = fileSize / MAX_UPLOAD_THREAD;

        int postSize = fileSize % MAX_UPLOAD_THREAD;
        int startPos = 0, endPos = 0;
        for (int i = 0; i < MAX_UPLOAD_THREAD; i++) {
            // 任务切割分配
            if (i < postSize) {
                endPos = startPos + everyThreadTaskSize + 1;

            } else {
                endPos = startPos + everyThreadTaskSize;
            }
            if (endPos > startPos && endPos <= fileSize) {
                executorService.execute(new UploadFileThread(ossClient, imgBucket, fileKeys.subList(startPos, endPos),
                                                             _files.subList(startPos, endPos), eTags));
            }
            startPos = endPos;
        }
        executorService.shutdown();
        while (!executorService.isTerminated()) {
            executorService.awaitTermination(10, TimeUnit.SECONDS);
        }
        if (eTags.size() != fileKeys.size()) {
            throw new IllegalStateException("writeFiles error");
        }
        return true;
    }

    private class UploadFileThread implements Runnable {

        private File         uploadFile;
        private String       bucket;
        private List<String> fileKeys;
        private List<File>   uploadFiles;
        private List<String> eTags;
        private OSSClient    client;

        UploadFileThread(OSSClient client, String bucket, List<String> fileKeys, List<File> uploadFiles,
                         List<String> eTags){
            this.uploadFile = uploadFile;
            this.bucket = bucket;
            this.fileKeys = fileKeys;
            this.uploadFiles = uploadFiles;
            this.eTags = eTags;
            this.client = client;
        }

        @Override
        public void run() {
            if (null != fileKeys && null != uploadFiles && uploadFiles.size() == fileKeys.size()) {
                int size = uploadFiles.size();
                for (int i = 0; i < size; ++i) {
                    try {
                        PutObjectResult putObjectResult = uploadFile(client, imgBucket, fileKeys.get(i),
                                                                     uploadFiles.get(i));
                        if (null != putObjectResult) {
                            eTags.add(putObjectResult.getETag());
                        } else {
                            logger.error("UploadFileThread error:" + fileKeys.get(i));
                        }
                    } catch (Exception e) {
                        logger.error("UploadFileThread error:", e);
                    }
                }

            }
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        if (StringUtil.isBlank(accesskeyId)) {
            accesskeyId = ALIYUN_ACCESSKEYID;
        }
        if (StringUtil.isBlank(accesskeySecret)) {
            accesskeySecret = ALIYUN_ACCESSKEYSECRET;
        }
        if (StringUtil.isBlank(imgBucket)) {
            imgBucket = ALIYUN_IMG_BUCKET_NAME;
        }
        if (StringUtil.isBlank(imgDomain)) {
            imgDomain = "http://style.boshijie-web.cn";
        } else {
            imgDomain = "http://" + imgDomain;
        }
        ossClient = new OSSClient(accesskeyId, accesskeySecret);

    }

}
